[IA64] support FPSWA hypercall
authorawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Thu, 25 May 2006 21:59:18 +0000 (15:59 -0600)
committerawilliam@xenbuild.aw <awilliam@xenbuild.aw>
Thu, 25 May 2006 21:59:18 +0000 (15:59 -0600)
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
xen/arch/ia64/xen/dom_fw.c
xen/arch/ia64/xen/efi_emul.c
xen/arch/ia64/xen/hypercall.c
xen/include/asm-ia64/dom_fw.h
xen/include/asm-ia64/domain.h

index b9941a253cea86f7fb1c75250c95437923140dd9..c44d634359860ba9d216371921229c0e3575ef2c 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/pal.h>
 #include <asm/sal.h>
 #include <asm/meminit.h>
+#include <asm/fpswa.h>
 #include <xen/compile.h>
 #include <xen/acpi.h>
 
@@ -59,6 +60,29 @@ dom_pa(unsigned long imva)
         }                                           \
     } while (0)
 
+// builds a hypercall bundle at domain physical address
+static void dom_fpswa_hypercall_patch(struct domain *d)
+{
+       unsigned long *entry_imva, *patch_imva;
+       unsigned long entry_paddr = FW_HYPERCALL_FPSWA_ENTRY_PADDR;
+       unsigned long patch_paddr = FW_HYPERCALL_FPSWA_PATCH_PADDR;
+
+#ifndef CONFIG_XEN_IA64_DOM0_VP
+       if (d == dom0) {
+               entry_paddr += dom0_start;
+               patch_paddr += dom0_start;
+       }
+#endif
+       ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, entry_paddr);
+       ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, patch_paddr);
+       entry_imva = (unsigned long *) domain_mpa_to_imva(d, entry_paddr);
+       patch_imva = (unsigned long *) domain_mpa_to_imva(d, patch_paddr);
+
+       *entry_imva++ = patch_paddr;
+       *entry_imva   = 0;
+       build_hypercall_bundle(patch_imva, d->arch.breakimm, FW_HYPERCALL_FPSWA, 1);
+}
+
 // builds a hypercall bundle at domain physical address
 static void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall)
 {
@@ -72,7 +96,6 @@ static void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsig
        build_hypercall_bundle(imva, d->arch.breakimm, hypercall, 1);
 }
 
-
 // builds a hypercall bundle at domain physical address
 static void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret)
 {
@@ -771,6 +794,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        struct ia64_sal_systab *sal_systab;
        struct ia64_sal_desc_entry_point *sal_ed;
        struct ia64_sal_desc_ap_wakeup *sal_wakeup;
+       fpswa_interface_t *fpswa_inf;
        efi_memory_desc_t *efi_memmap, *md;
        struct ia64_boot_param *bp;
        unsigned long *pfn;
@@ -812,6 +836,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        sal_systab  = (void *) cp; cp += sizeof(*sal_systab);
        sal_ed      = (void *) cp; cp += sizeof(*sal_ed);
        sal_wakeup  = (void *) cp; cp += sizeof(*sal_wakeup);
+       fpswa_inf   = (void *) cp; cp += sizeof(*fpswa_inf);
        efi_memmap  = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
        bp          = (void *) cp; cp += sizeof(*bp);
        pfn         = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
@@ -819,6 +844,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
 
        /* Initialise for EFI_SET_VIRTUAL_ADDRESS_MAP emulation */
        d->arch.efi_runtime = efi_runtime;
+       d->arch.fpswa_inf   = fpswa_inf;
 
        if (args) {
                if (arglen >= 1024)
@@ -962,6 +988,11 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
 
        sal_systab->checksum = -checksum;
 
+       /* Fill in the FPSWA interface: */
+       fpswa_inf->revision = fpswa_interface->revision;
+       dom_fpswa_hypercall_patch(d);
+       fpswa_inf->fpswa = (void *) FW_HYPERCALL_FPSWA_ENTRY_PADDR + start_mpaddr;
+
        i = 0;
        if (d == dom0) {
 #ifndef CONFIG_XEN_IA64_DOM0_VP
@@ -1045,7 +1076,7 @@ dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int f
        bp->console_info.num_rows = 25;
        bp->console_info.orig_x = 0;
        bp->console_info.orig_y = 24;
-       bp->fpswa = 0;
+       bp->fpswa = dom_pa((unsigned long) fpswa_inf);
        if (d == dom0) {
                // XXX CONFIG_XEN_IA64_DOM0_VP
                // initrd_start address is hard coded in start_kernel()
index 333a8cc61bb308ea9dbefc84cb101843b2ff2615..ccc8e35aeefc31d9a1f8f84c4cc936d82a3c48c2 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/pgalloc.h>
 #include <asm/vcpu.h>
 #include <asm/dom_fw.h>
+#include <asm/fpswa.h>
 #include <public/sched.h>
 
 extern unsigned long translate_domain_mpaddr(unsigned long);
@@ -75,6 +76,7 @@ efi_emulate_set_virtual_address_map(
        unsigned long *vfn;
        struct domain *d = current->domain;
        efi_runtime_services_t *efi_runtime = d->arch.efi_runtime;
+       fpswa_interface_t *fpswa_inf = d->arch.fpswa_inf;
 
        if (descriptor_version != EFI_MEMDESC_VERSION) {
                printf ("efi_emulate_set_virtual_address_map: memory descriptor version unmatched\n");
@@ -119,6 +121,12 @@ efi_emulate_set_virtual_address_map(
                EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_variable,EFI_SET_VARIABLE);
                EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
                EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->reset_system,EFI_RESET_SYSTEM);
+
+               vfn = (unsigned long *) domain_mpa_to_imva(d, (unsigned long) fpswa_inf->fpswa);
+               *vfn++ = FW_HYPERCALL_FPSWA_PATCH_INDEX * 16UL + md->virt_addr;
+               *vfn   = 0;
+               fpswa_inf->fpswa = (void *) (FW_HYPERCALL_FPSWA_ENTRY_INDEX * 16UL + md->virt_addr);
+               break;
        }
 
        /* The virtual address map has been applied. */
index 9b1183a732a7786460ee75c49767b14e2ddbccfb..0f68350661571cdd20830ab674066542bec231e9 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
 #include <asm/sal.h>   /* FOR struct ia64_sal_retval */
+#include <asm/fpswa.h> /* FOR struct fpswa_ret_t */
 
 #include <asm/vcpu.h>
 #include <asm/dom_fw.h>
@@ -181,12 +182,19 @@ fw_hypercall_ipi (struct pt_regs *regs)
        return;
 }
 
+static fpswa_ret_t
+fw_hypercall_fpswa (struct vcpu *v)
+{
+       return PSCBX(v, fpswa_ret);
+}
+
 static IA64FAULT
 fw_hypercall (struct pt_regs *regs)
 {
        struct vcpu *v = current;
        struct sal_ret_values x;
        efi_status_t efi_ret_value;
+       fpswa_ret_t fpswa_ret;
        IA64FAULT fault; 
        unsigned long index = regs->r2 & FW_HYPERCALL_NUM_MASK_HIGH;
 
@@ -253,6 +261,13 @@ fw_hypercall (struct pt_regs *regs)
            case FW_HYPERCALL_IPI:
                fw_hypercall_ipi (regs);
                break;
+           case FW_HYPERCALL_FPSWA:
+               fpswa_ret = fw_hypercall_fpswa (v);
+               regs->r8  = fpswa_ret.status;
+               regs->r9  = fpswa_ret.err0;
+               regs->r10 = fpswa_ret.err1;
+               regs->r11 = fpswa_ret.err2;
+               break;
            default:
                printf("unknown ia64 fw hypercall %lx\n", regs->r2);
                regs->r8 = do_ni_hypercall();
index f8acef7dc0c71d7915f2ebaac1f8d534a63557c4..8cab148d9b4d8761598fe9c0ecddae650dad9351 100644 (file)
 #define FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT_PADDR        FW_HYPERCALL_PADDR(FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT_INDEX)
 #define FW_HYPERCALL_EFI_RESET_SYSTEM_PADDR            FW_HYPERCALL_PADDR(FW_HYPERCALL_EFI_RESET_SYSTEM_INDEX)
 
+/*
+ * This is a hypercall number for IPI.
+ * A pseudo-entry-point is not presented to IPI hypercall. This hypercall number 
+ * is used in xen_send_ipi of linux-2.6-xen-sparse/arch/ia64/xen/hypercall.S.
+ */
+#define FW_HYPERCALL_IPI                               0x400UL
+
+/*
+ * This is a hypercall number for FPSWA.
+ * FPSWA hypercall uses 2 bundles for a pseudo-entry-point and a hypercall-patch.
+ */
+#define FW_HYPERCALL_FPSWA_ENTRY_INDEX                 0x83UL
+#define FW_HYPERCALL_FPSWA_PATCH_INDEX                 0x84UL
+#define FW_HYPERCALL_FPSWA_ENTRY_PADDR                 FW_HYPERCALL_PADDR(FW_HYPERCALL_FPSWA_ENTRY_INDEX)
+#define FW_HYPERCALL_FPSWA_PATCH_PADDR                 FW_HYPERCALL_PADDR(FW_HYPERCALL_FPSWA_PATCH_INDEX)
+#define FW_HYPERCALL_FPSWA                             0x500UL
+
 /* Hypercalls index bellow _FIRST_ARCH are reserved by Xen, while those above
    are for the architecture.
    Note: this limit was defined by Xen/ia64 (and not by Xen).²
 */
 #define FW_HYPERCALL_FIRST_ARCH                0x300UL
 
-#define FW_HYPERCALL_IPI               0x400UL
-
 /* Xen/ia64 user hypercalls.  Only used for debugging.  */
 #define FW_HYPERCALL_FIRST_USER                0xff00UL
 
index 466bcaf7e6d54de7c6852a26c2ee7c2db4bf1e68..3568bdf54d2da847a94cd2192e7e4a2b8d8bfa90 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/vmx_platform.h>
 #include <xen/list.h>
 #include <xen/cpumask.h>
+#include <asm/fpswa.h>
 
 extern void domain_relinquish_resources(struct domain *);
 
@@ -59,8 +60,12 @@ struct arch_domain {
     unsigned long initrd_start;
     unsigned long initrd_len;
     char *cmdline;
+    /* There are these for EFI_SET_VIRTUAL_ADDRESS_MAP emulation. */
     int efi_virt_mode;         /* phys : 0 , virt : 1 */
+    /* Metaphysical address to efi_runtime_services_t in domain firmware memory is set. */
     void *efi_runtime;
+    /* Metaphysical address to fpswa_interface_t in domain firmware memory is set. */
+    void *fpswa_inf;
 };
 #define xen_vastart arch.xen_vastart
 #define xen_vaend arch.xen_vaend
@@ -109,6 +114,7 @@ struct arch_vcpu {
     //for phycial  emulation
     unsigned long old_rsc;
     int mode_flags;
+    fpswa_ret_t fpswa_ret;     /* save return values of FPSWA emulation */
     struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */
 };